package com.ruoyi.attendance.service.impl;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import com.ruoyi.attendance.domain.AttendanceStatusVo;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.enums.SignStatus;
import com.ruoyi.common.exception.attendance.AttendanceException;
import com.ruoyi.common.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.attendance.mapper.SignInfoViewMapper;
import com.ruoyi.attendance.domain.SignInfoView;
import com.ruoyi.attendance.service.ISignInfoViewService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 考勤记录Service业务层处理
 *
 * @author Weiney
 * @date 2025-04-12
 */
@Service
public class SignInfoViewServiceImpl implements ISignInfoViewService {
    private static final Logger log = LoggerFactory.getLogger(SignInfoViewServiceImpl.class);
    @Autowired
    private SignInfoViewMapper signInfoViewMapper;

    /**
     * 查询考勤记录
     *
     * @param signId 考勤记录主键
     * @return 考勤记录
     */
    @Override
    public SignInfoView selectSignInfoViewBySignId(Long signId) {
        return signInfoViewMapper.selectSignInfoViewBySignId(signId);
    }

    /**
     * 查询考勤记录列表
     *
     * @param signInfoView 考勤记录
     * @return 考勤记录
     */
    @Override
    @DataScope(deptAlias = "t", userAlias = "t")
    public List<SignInfoView> selectSignInfoViewList(SignInfoView signInfoView) {
        return signInfoViewMapper.selectSignInfoViewList(signInfoView);
    }

    /**
     * 考勤信息统计
     *
     * @param signInfoView 考勤记录
     * @return 考勤记录
     */
    @Override
    @DataScope(deptAlias = "t", userAlias = "t")
    public List<SignInfoView> selectSignStatistic(SignInfoView signInfoView) {
        return signInfoViewMapper.selectSignStatistic(signInfoView);
    }

    /**
     * 查询本人考勤记录列表
     *
     * @param signInfoView 考勤记录
     * @return 考勤记录
     */
    @Override
    public List<SignInfoView> selectSignInfoViewListForOwn(SignInfoView signInfoView) {
        return signInfoViewMapper.selectSignInfoViewListForOwn(signInfoView);
    }


    private List<SignInfoView> getOwnSignInfoList(Long userId, Long deptId){
        // 查询本人当天考勤记录列表
        Date currentDate = DateUtils.getNowDate();
        SignInfoView queryCurrentDateList = new SignInfoView();
        queryCurrentDateList.setUserId(userId);
        queryCurrentDateList.setDeptId(deptId);
        queryCurrentDateList.setSignTime(currentDate);
        return signInfoViewMapper.selectOwnSignInfoList(queryCurrentDateList);
    }

    /**
     * 新增考勤记录
     *
     * @param signInfoView 考勤记录
     * @return 结果
     */
    @Override
    @Transactional
    public int insertSignInfoView(SignInfoView signInfoView) {
        /*
            考勤规则：上班签到一次，下班签到一次，不可重复签到
                - 签到状态：【准时签到】【准时签退】【迟到】【早退】 【考勤异常】
            1. 如果 当天考勤记录小于2条
                - 获取考勤的时间范围
                - 如果 当前时间 < 当天12:00
                    如果 当前时间在签到的时间范围内，签到状态设置为 【准时签到】
                    否则 签到状态设置为 【迟到】
                  否则 当前时间 > 当天12:00
                    当前时间在签退的时间范围内，签到状态设置为 【准时签退】
                    否则如果 当前时间小于签退范围，签到状态设置为【早退】
                    否则如果 当前时间大于签退范围，则签到状态设置为【考勤异常】
            2. 否则 抛出考勤异常
            3. 执行签到
         */
        Date currentDate = DateUtils.getNowDate(); // 当天日期
        List<SignInfoView> currentDateList = getOwnSignInfoList(signInfoView.getUserId(), signInfoView.getDeptId());
        // 检查当天考勤记录列表是否不为空且记录数量为 2
        if (!currentDateList.isEmpty() && currentDateList.size() == 2) {
            // 当列表不为空且元素数量为 2 时执行的代码
            throw new AttendanceException("禁止重复插入考勤记录！");
        } else if(currentDateList.size() > 2){
            throw new AttendanceException("考勤严重错误，请联系管理员！");
        } else {
            // 考勤状态正常，可以按规则考勤
            // 获取考勤的时间范围
            List<SysDictData> timeRangeList = signInfoViewMapper.selectAttendanceTimeRange();
            String startSignStartTimeStr = null;
            String startSignEndTimeStr = null;
            String endSignStartTimeStr = null;
            String endSignEndTimeStr = null;
            for (SysDictData data : timeRangeList) {
                if ("0".equals(data.getDictValue())) {
                    startSignStartTimeStr = data.getDictLabel();
                } else if ("1".equals(data.getDictValue())) {
                    startSignEndTimeStr = data.getDictLabel();
                } else if ("2".equals(data.getDictValue())) {
                    endSignStartTimeStr = data.getDictLabel();
                } else if ("3".equals(data.getDictValue())) {
                    endSignEndTimeStr = data.getDictLabel();
                }
            }
            int count = 0; // 执行结果记录数

            if (startSignStartTimeStr != null && startSignEndTimeStr != null && endSignStartTimeStr != null && endSignEndTimeStr != null) {
                LocalTime startSignStartTime = LocalTime.parse(startSignStartTimeStr);
                LocalTime startSignEndTime = LocalTime.parse(startSignEndTimeStr);
                LocalTime endSignStartTime = LocalTime.parse(endSignStartTimeStr);
                LocalTime endSignEndTime = LocalTime.parse(endSignEndTimeStr);
                LocalTime currentTime = LocalTime.now(); // 当前时间
                SignStatus signStatus = null;
                // 上午签到逻辑，如果 当前时间 < 当天12:00
                if (currentTime.isBefore(LocalTime.of(12, 0))) {
                    if (currentTime.isAfter(startSignStartTime) && currentTime.isBefore(startSignEndTime)) {
                        // 如果 当前时间在签到的时间范围内，签到状态设置为 【准时签到】
                        signStatus = SignStatus.ON_TIME;
                    } else {
                        // 否则 签到状态设置为 【迟到】
                        signStatus = SignStatus.LATE;
                    }
                } else { // 下班签退逻辑 当前时间 > 当天12:00
                    if (currentTime.isAfter(endSignStartTime) && currentTime.isBefore(endSignEndTime)) {
                        // 当前时间在签退的时间范围内，签到状态设置为 【准时签退】
                        signStatus = SignStatus.ON_TIME_SIGN_OUT;
                    } else if (currentTime.isBefore(endSignStartTime)) {
                        // 否则如果 当前时间小于签退范围，签到状态设置为【早退】
                        signStatus = SignStatus.EARLY_LEAVE;
                    } else if (currentTime.isAfter(endSignEndTime)) {
                        // 否则如果 当前时间大于签退范围，则签到状态设置为【考勤异常】
                        signStatus = SignStatus.ATTENDANCE_EXCEPTION;
                    }
                }

                if (signStatus != null) { // 签到状态设置成功，执行签到记录
                    signInfoView.setSignStatus(signStatus.getCode());
                    signInfoView.setSignTime(currentDate);
                    count = signInfoViewMapper.insertSignInfoView(signInfoView);
                    log.info("考勤记录插入成功，用户id: {}，考勤时间：{}，考勤状态：{}", signInfoView.getUserId(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, signInfoView.getSignTime()), signStatus.getInfo());
                } else {
                    throw new AttendanceException("签到状态获取有误，请联系管理员！");
                }
                return count;
            } else {
                throw new AttendanceException("请按规则设置考勤时间");
            }
        }
    }

    /**
     * 修改考勤记录
     *
     * @param signInfoView 考勤记录
     * @return 结果
     */
    @Override
    public int updateSignInfoView(SignInfoView signInfoView) {
        return signInfoViewMapper.updateSignInfoView(signInfoView);
    }

    /**
     * 批量删除考勤记录
     *
     * @param signIds 需要删除的考勤记录主键
     * @return 结果
     */
    @Override
    public int deleteSignInfoViewBySignIds(Long[] signIds) {
        return signInfoViewMapper.deleteSignInfoViewBySignIds(signIds);
    }

    /**
     * 删除考勤记录信息
     *
     * @param signId 考勤记录主键
     * @return 结果
     */
    @Override
    public int deleteSignInfoViewBySignId(Long signId) {
        return signInfoViewMapper.deleteSignInfoViewBySignId(signId);
    }

    @Override
    public AttendanceStatusVo selectAttendanceStatus(Long userId, Long deptId) {
        List<SignInfoView> signInfoList = getOwnSignInfoList(userId, deptId);
        if (signInfoList.isEmpty()) {
            // 未打卡
            return new AttendanceStatusVo(null, null, false, false, null, null);
        } else {
            AttendanceStatusVo attendanceStatus = new AttendanceStatusVo();

            Date clockInTime = null;
            Date clockOutTime = null;

            for (SignInfoView signInfo : signInfoList) {
                Date signTime = signInfo.getSignTime();
                if (signTime == null) {
                    continue; // 跳过时间为空的记录
                }
                LocalTime time = LocalDateTime.ofInstant(signTime.toInstant(), ZoneId.systemDefault()).toLocalTime();
                if (time.getHour() < 12) {
                    attendanceStatus.setSignInStatus(signInfo.getSignStatus()); // 签到状态
                    clockInTime = signTime; // 上午时间（最多一条，直接覆盖，根据需求不会重复）
                } else {
                    attendanceStatus.setSignOutStatus(signInfo.getSignStatus()); // 签退状态
                    clockOutTime = signTime; // 下午时间（最多一条，直接覆盖，根据需求不会重复）
                }
            }

            attendanceStatus.setClockInTime(clockInTime);
            attendanceStatus.setClockOutTime(clockOutTime);
            attendanceStatus.setClockInStatus(Objects.nonNull(clockInTime));
            attendanceStatus.setClockOutStatus(Objects.nonNull(clockOutTime));

            return attendanceStatus;
        }
    }
}
